import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/suggest_date_entity.dart';
import 'package:finance_app/src/http_service/http_setting_service.dart';
import 'package:finance_app/src/utils/report_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/date_time_select_bottom_sheet.dart';
import 'package:r_datetime_picker/r_datetime_picker.dart';

mixin ReportDateSelectMixin<T> on BaseProvider<T> {
  DateTime from;
  DateTime to;

  // 91
  DateTime month;

  int get type;

  List<DateTime> monthList = [];
  List<String> datePopList = [
    // S.current.this_week,
    // S.current.this_month,
    // S.current.this_quarter,
    S.current.this_financial_year,
    S.current.custom,
  ];
  String currentSelectDatePop;

  //当前+ 后三个季度
  List<String> lastQuarter = [];

  @override
  void initState() {
    initChangeDatePop();
    super.initState();
  }

  void initChangeDatePop() {
    if (type == 71 ||
        type == 72 ||
        type == 73 ||
        type == 74 ||
        type == 75 ||
        type == ReportUtils.GeneralLedgerDetail) {
      datePopList = [
        // S.current.this_month,
        S.current.this_financial_year,
        S.current.custom,
      ];
      // currentSelectDatePop = datePopList.first;
    }
    if (currentSelectDatePop == null) {
      currentSelectDatePop = S.current.this_financial_year;
    }

    if (from == null && to == null) onChangeDatePop();
  }

  void onRequestRefresh();

  void onChangeDate(String value) {
    if (currentSelectDatePop == value) return;
    currentSelectDatePop = value;
    onChangeDatePop();
    update();
    if (currentSelectDatePop != S.current.custom) {
      onRequestRefresh();
    }
  }

  void onSelectFrom() {
    if (currentSelectDatePop != S.current.custom) return;
    obtainContext?.call((context) async {
      final result =
          await showDateTimeSelectBottomSheet(context, S.current.from, from);
      if (result != null) {
        if (to != null) {
          if (to.isAfter(result)) {
            from = result;
          } else {
            from = to;
          }
        } else {
          from = result;
        }
        update();
        checkFromToDateTimeRefresh();
      }
    });
  }

  void onSelectTo() {
    if (currentSelectDatePop != S.current.custom) return;
    obtainContext?.call((context) async {
      final result =
          await showDateTimeSelectBottomSheet(context, S.current.to, to);
      if (result != null) {
        if (from != null) {
          if (from.isBefore(result)) {
            to = result;
          } else {
            to = from;
          }
        } else {
          to = result;
        }
        update();
        checkFromToDateTimeRefresh();
      }
    });
  }

  void checkFromToDateTimeRefresh() {
    if (from == null || to == null) return;
    onRequestRefresh();
  }

  void _onWeek(DateTime now) {
    int nowWeekDay = now.weekday;
    final weekStart = now.subtract(Duration(days: nowWeekDay));
    final weekEnd = now.add(Duration(days: 7 - nowWeekDay));
    from = weekStart;
    to = weekEnd;
  }

  void _onMonth(DateTime now) {
    int year = now.year;
    int month = now.month;
    final monthStart = DateTime(year, month, 1);
    final monthEnd =
        DateTime(year, month, RDatetimeUtils.getDaysInMonth(year, month));
    from = monthStart;
    to = monthEnd;
  }

  void _onQuarter(DateTime now) {
    int year = now.year;
    int month = now.month;
    List<int> quarter = [1, 3, 6, 9, 12];
    int endMonth =
        quarter.firstWhere((element) => element >= month, orElse: () => null);
    int startMonth = quarter[quarter.indexOf(endMonth) - 1];
    final quarterStart =
        DateTime(year, startMonth != 1 ? (startMonth + 1) : 1, 1);
    final quarterEnd =
        DateTime(year, endMonth, RDatetimeUtils.getDaysInMonth(year, endMonth));
    from = quarterStart;
    to = quarterEnd;
  }

  void _onYear(DateTime now) {
    // int year = now.year;
    // int month = now.month;
    // final yearStart = DateTime(year, 1, 1);
    // final yearEnd =
    //     DateTime(year, 12, RDatetimeUtils.getDaysInMonth(year, month));
    from = DateTime.tryParse(Config.currentFY.startDate);
    to = DateTime.tryParse(Config.currentFY.endDate);
  }

  void _onCustom() {
    from = null;
    to = null;
  }

  void onChangeDatePop() {
    final now = DateTime.now();
    if (currentSelectDatePop == S.current.this_week) {
      _onWeek(now);
    } else if (currentSelectDatePop == S.current.this_month) {
      _onMonth(now);
    } else if (currentSelectDatePop == S.current.this_quarter) {
      _onQuarter(now);
    } else if (currentSelectDatePop == S.current.this_financial_year) {
      _onYear(now);
    } else if (currentSelectDatePop == S.current.custom) {
      _onCustom();
    } else {
      _onCustom();
    }
  }

  Future<void> initMonthListDatePop() async {
    if (monthList.length > 0) return;

    if (type == 88) {
      await post(HttpSettingService.getSuggestTime('payslip_list'),
          onSuccess: (result) {
        SuggestDateListEntity suggestDateEntity =
            getEntityFromResult<SuggestDateListEntity>(result);
        if (suggestDateEntity?.typeDate?.length == 0) {
          month = DateTime.tryParse(suggestDateEntity.financialYearDate.start);
          update();
          return;
        }
        if (suggestDateEntity?.typeDate != null) {
          month = DateTime.tryParse(suggestDateEntity?.typeDate?.first?.start);
        } else {
          month = DateTime.tryParse(Config.currentFY.startDate);
        }
        if (suggestDateEntity?.typeDate != null) {
          for (var item in suggestDateEntity?.typeDate) {
            monthList.add(DateTime.tryParse(item.start));
          }
        }
      });
      update();

      return;
    }

    DateTime now = DateTime.parse(Config.currentFY.endDate);
    DateTime nowFirst = DateTime(now.year, now.month, 1);
    month = nowFirst;
    monthList.add(nowFirst);
    int months = 12;

    for (int i = 0; i < months; i++) {
      final reduce = nowFirst.subtract(Duration(days: 1));
      nowFirst = DateTime(reduce.year, reduce.month, 1);
      monthList.add(nowFirst);
    }
  }

  void onChangeMonthDate(DateTime value) {
    if (month == value) return;
    month = value;
    update();
    onRequestRefresh();
  }
}
